/*
 * Lexer and Parser 
 * Random Data Generator Language (RDGL)
 * by Navid Azimi, Summer 2007
 */

header {package rdgl.antlr;}
class RDGLLexer extends Lexer;

options {
    k = 2;  
    charVocabulary = '\3'..'\377';
    testLiterals = false;
    exportVocab = RDGL;
}

protected
DIGIT		: '0'..'9';

protected
LETTER		: ('a'..'z' | 'A'..'Z');

POUND		: '#';	// number
AT			: '@';	// letter
AMPERSAND	: '&';	// alphanumeric
DOLLAR		: '$';	// symbol
PERCENT		: '%';	// wildcard
ASTERISK	: '*';	// enum (nullable)
QUESTION	: '?';	// enum
L_BRACKET	: '[';
R_BRACKET	: ']';
L_PAREN 	: '(';
R_PAREN 	: ')';
L_SQUIGLY	: '{';
R_SQUIGLY	: '}';
COMMA		: ',';
COLON		: ':';
MINUS		: '-';

NUMBER		: (DIGIT)+;
WORD		: (LETTER)+;

WS      	: (' ' | '\t')+ { $setType(Token.SKIP); };
NL      	: ('\n' | ('\r' '\n') => '\r' '\n' | '\r') 
        	    { $setType(Token.SKIP); newline(); }
        	;

/*****************************************************************************/

class RDGLParser extends Parser;

options {
    k = 2;
    buildAST = true;
    exportVocab = RDGL;
}

tokens {
	PROGRAM;
	STATEMENT;
	ENUMERATION;
	VALUES_LIST;
	RANGE;
	LENGTH;
	LOOP;
}

program
	: (loop | enumeration | expression)+
		{#program = #([PROGRAM, "PROGRAM"], program); }
	;

numbers_range
	: NUMBER MINUS^ NUMBER
	;

values_list
	: (NUMBER | numbers_range) (COMMA! (NUMBER | numbers_range))*
		{#values_list = #([VALUES_LIST, "VALUES_LIST"], values_list); }
	;

length
	: L_BRACKET! values_list R_BRACKET!
		{#length = #([LENGTH, "LENGTH"], length); }
	;

range
	: L_SQUIGLY! values_list R_SQUIGLY!
		{#range = #([RANGE, "RANGE"], range); }
	;

expression
	: POUND^ (range | length)?
	| (AT^ | AMPERSAND^ | DOLLAR^ | PERCENT^ ) (length)?
	;

values
	: (WORD | NUMBER) (COMMA! (WORD | NUMBER))*
	;

enumeration
	: (QUESTION^ | ASTERISK^) L_SQUIGLY! values R_SQUIGLY!
		{#enumeration = #([ENUMERATION, "ENUMERATION"], enumeration); }
	;

expr_block
	: (expression)+
		{#expr_block = #([STATEMENT, "STATEMENT"], expr_block); }
	;

loop
	: L_PAREN! values_list COLON! expr_block R_PAREN!
		{#loop = #([LOOP, "LOOP"], loop); }
	;
